package com.example.student.security;

import com.example.student.config.JwtConfig;
import com.example.student.config.SecurityPropertiesConfig;
import com.example.student.entity.SysUser;
import com.example.student.mapper.SysUserMapper;
import com.example.student.security.exception.JwtAuthenticationException;
import com.example.student.service.impl.JwtTokenServiceImpl;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.security.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class JwtAuthorizationFilter extends OncePerRequestFilter {

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthorizationFilter.class);
    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    private final JwtConfig jwtConfig;
    private final JwtTokenServiceImpl tokenService;
    
    @Resource
    private UserDetailsServiceImpl userDetailsService;
    
    @Resource
    private SysUserMapper userMapper;
    
    @Resource
    private SecurityPropertiesConfig securityPropertiesConfig;

    public JwtAuthorizationFilter(JwtConfig jwtConfig, JwtTokenServiceImpl tokenService) {
        this.jwtConfig = jwtConfig;
        this.tokenService = tokenService;
    }
    
    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        // 对登录相关的路径不进行JWT验证
        String path = request.getRequestURI();
        
        // 直接检查是否是登录请求
        if (path.equals("/api/auth/login")) {
            logger.info("直接放行登录请求: {}", path);
            return true;
        }
        
        // 检查路径是否在配置的permitAll列表中
        if (securityPropertiesConfig != null && securityPropertiesConfig.getPermitAll() != null) {
            for (String permitUrl : securityPropertiesConfig.getPermitAll()) {
                if (pathMatcher.match(permitUrl, path)) {
                    logger.debug("Path {} is permitted by configuration {}", path, permitUrl);
                    return true;
                }
            }
        }
        
        // 以下是原有的硬编码配置
        return pathMatcher.match("/auth/**", path) || 
               pathMatcher.match("/api/auth/**", path) ||
               pathMatcher.match("/swagger-ui.html", path) || 
               pathMatcher.match("/swagger-resources/**", path) || 
               pathMatcher.match("/v2/api-docs", path) || 
               pathMatcher.match("/webjars/**", path) ||
               pathMatcher.match("/druid/**", path);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        try {
            // 记录请求的基本信息
            logger.debug("Processing request: {} {}", request.getMethod(), request.getRequestURI());
            
            // 再次检查是否是登录请求，如果是，直接放行
            if (request.getRequestURI().equals("/api/auth/login")) {
                logger.info("登录请求直接放行 - 在doFilterInternal中再次检查");
                chain.doFilter(request, response);
                return;
            }
            
            // 记录所有请求头
            if (logger.isDebugEnabled()) {
                Enumeration<String> headerNames = request.getHeaderNames();
                if (headerNames != null) {
                    List<String> headers = Collections.list(headerNames);
                    logger.debug("Request headers: {}", headers.stream()
                            .map(name -> name + "=" + request.getHeader(name))
                            .collect(Collectors.joining(", ")));
                }
            }

            String token = tokenService.getTokenFromRequest(request);
            logger.debug("Extracted token: {}", token);

            if (StringUtils.hasText(token)) {
                try {
                    // 验证token是否有效（包括JWT格式验证和Redis验证）
                    if (tokenService.validateToken(token)) {
                        Claims claims = tokenService.getClaimsFromToken(token);
                        String username = claims.get("username", String.class);
                        logger.debug("Extracted username from token: {}", username);
                        
                        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                            try {
                                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                                logger.debug("Loaded user details for username: {}", username);
                                
                                // 创建身份认证令牌
                                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                                        userDetails, null, userDetails.getAuthorities());
                                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                                
                                // 设置认证上下文
                                SecurityContextHolder.getContext().setAuthentication(authentication);
                            } catch (Exception e) {
                                // 用户不存在或其他异常
                                String errorMessage = "用户信息已变更，请重新登录";
                                if (e.getMessage() != null) {
                                    if (e.getMessage().contains("用户不存在")) {
                                        errorMessage = "用户不存在或已被删除";
                                    } else if (e.getMessage().contains("禁用")) {
                                        errorMessage = "账号已被禁用";
                                    }
                                }
                                request.setAttribute("auth_error_message", errorMessage);
                                throw new JwtAuthenticationException(errorMessage);
                            }
                        } else {
                            request.setAttribute("auth_error_message", "无效的用户信息，请重新登录");
                        }
                    } else {
                        // token无效（可能是JWT格式错误、签名错误或Redis中不存在）
                        request.setAttribute("auth_error_message", "登录凭证已失效，请重新登录");
                        throw new JwtAuthenticationException("无效的token");
                    }
                } catch (ExpiredJwtException e) {
                    logger.error("Token已过期", e);
                    request.setAttribute("auth_error_message", "登录已过期，请重新登录");
                    throw new JwtAuthenticationException("登录已过期，请重新登录");
                } catch (SignatureException e) {
                    logger.error("无效的token签名", e);
                    request.setAttribute("auth_error_message", "无效的登录凭证，请重新登录");
                    throw new JwtAuthenticationException("无效的token签名");
                } catch (MalformedJwtException e) {
                    logger.error("无效的token格式", e);
                    request.setAttribute("auth_error_message", "无效的登录凭证，请重新登录");
                    throw new JwtAuthenticationException("无效的token格式");
                } catch (UnsupportedJwtException e) {
                    logger.error("不支持的token类型", e);
                    request.setAttribute("auth_error_message", "无效的登录凭证，请重新登录");
                    throw new JwtAuthenticationException("不支持的token类型");
                } catch (IllegalArgumentException e) {
                    logger.error("token参数为空", e);
                    request.setAttribute("auth_error_message", "登录凭证缺失，请重新登录");
                    throw new JwtAuthenticationException("token参数为空");
                }
            } else {
                logger.debug("No valid token found in request");
                request.setAttribute("auth_error_message", "请先登录");
            }

            chain.doFilter(request, response);
        } catch (JwtAuthenticationException e) {
            logger.error("JWT认证异常", e);
            SecurityContextHolder.clearContext();
            // 不需要再抛出异常，只需要设置好错误信息，后续会由JwtAuthenticationEntryPoint处理
            request.setAttribute("auth_error_message", e.getMessage());
            // 让过滤器链继续执行，这样会由JwtAuthenticationEntryPoint处理认证异常
            chain.doFilter(request, response);
        }
    }
} 